﻿/*
 * This file is part of MonoStrategy.
 *
 * Copyright (C) 2010-2011 Christoph Husse
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors: 
 *      # Christoph Husse
 * 
 * Also checkout our homepage: http://monostrategy.codeplex.com/
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MonoStrategy.RenderSystem;

namespace MonoStrategy
{
    public class AnimationUtilities : VisualUtilities
    {

        /// <summary>
        /// Schedules the given task for execution at the next rendering cycle. 
        /// </summary>
        protected override void SynchronizeTaskImpl(Procedure inTask)
        {
            Program.TerrainRenderer.SynchronizeTask(inTask);
        }

        protected override void SynchronizeTaskImpl(long inDurationMillis, Procedure inTask)
        {
            Program.TerrainRenderer.SynchronizeTask(inDurationMillis, inTask);
        }

        protected override void HideImpl(Movable inMovable)
        {
            if (inMovable.IsMarkedForRemoval)
                return;

            Program.TerrainRenderer.SynchronizeTask(() =>
            {
                VisualMovable visualizer = inMovable.UserContext as VisualMovable;

                Program.TerrainRenderer.RemoveVisual(visualizer.Visual);
                visualizer.Visual = null;
            });
        }

        protected override void DirectedAnimationImpl(
            Movable inMovable,
            String inClass,
            Direction? inDirectionOverride,
            bool inRestart,
            bool inRepeat)
        {
            if (inMovable.IsMarkedForRemoval)
                return;

            Program.TerrainRenderer.SynchronizeTask(() =>
            {
                VisualMovable visualizer = inMovable.UserContext as VisualMovable;
                var anim = visualizer.Visual;

                if (visualizer.Visual != null)
                {
                    if (anim.Class.Name != inClass)
                    {
                        Program.TerrainRenderer.RemoveVisual(anim);
                        visualizer.Visual = null;
                    }
                }

                if (visualizer.Visual == null)
                {
                    anim = Program.TerrainRenderer.CreateMovableOrientedAnimation(inClass, inMovable, 2);
                    visualizer.Visual = anim;
                    anim.UserContext = visualizer;
                }

                if (inRestart)
                    anim.ResetTime();

                anim.IsRepeated = inRepeat;
                anim.DirectionOverride = inDirectionOverride;
            });
        }

        protected override void AnimateImpl(
            Movable inMovable,
            String inClass,
            bool inRestart,
            bool inRepeat)
        {
            if (inMovable.IsMarkedForRemoval)
                return;

            Program.TerrainRenderer.SynchronizeTask(() =>
            {
                VisualMovable visualizer = inMovable.UserContext as VisualMovable;
                var anim = visualizer.Visual;

                if (visualizer.Visual != null)
                {
                    if (anim.Class.Name != inClass)
                    {
                        Program.TerrainRenderer.RemoveVisual(anim);
                        visualizer.Visual = null;
                    }
                }

                if (visualizer.Visual == null)
                {
                    anim = visualizer.Visual = Program.TerrainRenderer.CreateMovableOrientedAnimation(inClass, inMovable, 2);
                    anim.UserContext = visualizer;
                }

                if (inRestart)
                    anim.ResetTime();

                anim.IsRepeated = inRepeat;
                anim.DirectionOverride = null;
            });
        }

        protected override void AnimateAroundCenterImpl(
            Point inCenter,
            String inAnimationClass,
            String inAnimationSet)
        {
            var animClass = AnimationLibrary.Instance.FindClass(inAnimationClass);
            var anim = Program.TerrainRenderer.CreateAnimation(animClass, new PositionTracker() { Position = CyclePoint.FromGrid(inCenter) }, 1.0f);
            var animSet = animClass.FindSet(inAnimationSet);

            anim.IsCentered = true;
            anim.IsRepeated = false;
            anim.ResetTime();

            anim.Play(animSet);

            SynchronizeTask(animSet.DurationMillis, () => { Program.TerrainRenderer.RemoveVisual(anim); });
        }

        protected override int GetDurationMillisImpl(Movable inMovable, String inAnimClass)
        {
            return (int)AnimationLibrary.Instance.FindClass(inAnimClass).Sets.Max(e => e.DurationMillis);
        }

        protected override bool HasAnimationImpl(Movable inMovable, String inAnimClass)
        {
            return AnimationLibrary.Instance.HasClass(inAnimClass);
        }

        protected override bool HasAnimationImpl(Foilage inFoilage, String inAnimClass)
        {
            return AnimationLibrary.Instance.FindClass(inFoilage.Type.ToString()).HasSet(inAnimClass);
        }

        protected override int GetDurationMillisImpl(Foilage inFoilage, String inState)
        {
            return (int)AnimationLibrary.Instance.FindClass(inFoilage.Type.ToString()).FindSet(inState).DurationMillis;
        }

        protected override void AnimateImpl(
            Foilage inFoilage,
            String inState,
            bool inRestart,
            bool inRepeat)
        {
            Program.TerrainRenderer.SynchronizeTask(() =>
            {
                VisualFoilage visualizer = inFoilage.UserContext as VisualFoilage;
                var anim = visualizer.Visual;

                if (anim != null)
                {
                    anim.Play(inState);
                    anim.IsRepeated = inRepeat;

                    if (inRestart)
                        anim.ResetTime();
                }
            });
        }

        protected override void AnimateImpl(Stone inStone)
        {
            Program.TerrainRenderer.SynchronizeTask(() =>
            {
                VisualStone visualizer = inStone.UserContext as VisualStone;
                var anim = visualizer.Visual;

                anim.Play(inStone.ActualStones.ToString());
            });
        }

        protected override void ShowErrorImpl(string inMessage)
        {
            System.Windows.Forms.MessageBox.Show(inMessage);
        }

        protected override void ShowMessageImpl(string inMessage)
        {
            System.Windows.Forms.MessageBox.Show(inMessage);
        }

        protected override void AnimateImpl(BaseBuilding inBuilding, string inClass)
        {
            Program.TerrainRenderer.SynchronizeTask(() =>
            {
                VisualBuilding visualizer = inBuilding.UserContext as VisualBuilding;
                var anim = visualizer.Visual;

                if (anim != null)
                {
                    if (inClass != null)
                    {
                        anim.Play("Flag", inClass);
                        anim.IsRepeated = true;
                        anim.ResetTime();
                    }
                    else
                    {
                        anim.Play("Flag");
                        anim.IsRepeated = true;
                    }
                }
            });
        }

        protected override int GetDurationMillisImpl(BaseBuilding inBuilding, string inAnimClass)
        {
            return (int)AnimationLibrary.Instance.FindClass(inBuilding.Config.AnimationClass).FindSet(inAnimClass).DurationMillis;
        }

        protected override bool HasAnimationImpl(BaseBuilding inBuilding, string inAnimClass)
        {
            return AnimationLibrary.Instance.FindClass(inBuilding.Config.AnimationClass).HasSet(inAnimClass);
        }
    }
}
